package com.javasm.duanju.service.impl;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.javasm.duanju.dto.ExportDTO;
import com.javasm.duanju.dto.UploadVideoDTO;
import com.javasm.duanju.entity.DraftVideoItem;
import com.javasm.duanju.entity.Video;
import com.javasm.duanju.entity.VideoItem;
import com.javasm.duanju.enums.VideoStatus;
import com.javasm.duanju.service.DraftVideoItemService;
import com.javasm.duanju.service.VideoItemService;
import com.javasm.duanju.service.VideoService;
import com.javasm.duanju.vo.ItemVO;
import com.javasm.duanju.vo.VideoInfoVO;
import com.javasm.duanju.vo.VideoVo;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import utils.BeanUtils;
import com.javasm.duanju.dao.DraftVideoDao;
import com.javasm.duanju.dto.VideoBaseDTO;
import com.javasm.duanju.entity.DraftVideo;
import com.javasm.duanju.service.DraftVideoService;
import com.javasm.pk.PkClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * (DraftVideo)表服务实现类
 *
 * @author makejava
 * @since 2025-02-26 19:29:26
 */
@Service("draftVideoService")
public class DraftVideoServiceImpl extends ServiceImpl<DraftVideoDao, DraftVideo> implements DraftVideoService {

    public static final String VIDEO_ID_TYPE="VIDEO";
    public static final String VIDEO_ITEM_ID_TYPE="VIDEO_ITEM";
    public static final long VIDEO_BASE_ID=1000000L;
    public static final long VIDEO_ITEM_BASE_ID=100000000L;
    public  static  final  String OSS_VIDEO_PREFIX="dj/video/";
    @Autowired
    private PkClient pkClient;
  @Autowired
  DraftVideoItemService draftVideoItemService;
  @Autowired
  QiNiuService qiNiuService;
  @Autowired
    RedisTemplate<String,Object> redisTemplate;
  @Autowired
    VideoService videoService;

  @Autowired
    VideoItemService videoItemService;


    @Override
    public long addVideo(VideoBaseDTO videoBaseDTO) {
//      检验短剧名是否重复
                String videoBaseDTOName = videoBaseDTO.getName();
        LambdaQueryWrapper<DraftVideo> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DraftVideo::getName,videoBaseDTOName);
        List<DraftVideo> draftVideoList = this.list(lambdaQueryWrapper);
        if (draftVideoList.size()>0){
            throw new RuntimeException("短剧名存在");
        }

//        进行添加操作
        DraftVideo draftVideo = BeanUtils.copyBean(videoBaseDTO, DraftVideo.class);
        LocalDateTime now = LocalDateTime.now();
        draftVideo.setCreateTime(now);
        draftVideo.setUpdateTime(now);
        draftVideo.setCreater(100L);//TODO 做完认证服务后，改为获取当前登录用户
        draftVideo.setUpdater(100L);//TODO 做完认证服务后，改为获取当前登录用户
//        调用主键生成服务
        draftVideo.setId(VIDEO_BASE_ID+pkClient.getLongKey(VIDEO_ID_TYPE));//TODO 调用主键生成服务的流水号1000001
        draftVideo.setStatus(VideoStatus.DRAFT.getStatus());
        //        draftVideo.setShortName();//TODO 做搜索的时候再说
        //移动封面图到短剧文件夹 64/feng/[短剧id]/[短剧id].jpg
        String oldPath = videoBaseDTO.getCoverUrl();
        String ext = oldPath.substring(oldPath.lastIndexOf("."));
        String newPath = "dj/video/" + draftVideo.getId() +"/" + draftVideo.getId() + ext;
        qiNiuService.move(oldPath,newPath);
        draftVideo.setCoverUrl(newPath);

//        保存短剧信息.
        List<Long> longRange = pkClient.getLongRange(VIDEO_ITEM_ID_TYPE, videoBaseDTO.getTotalCount());
        Long firstId = longRange.get(0);
       List<DraftVideoItem> list= new ArrayList<>();
        for(int i = 0;i<draftVideo.getTotalCount();i++){
            DraftVideoItem videoItem = new DraftVideoItem();
            videoItem.setId(VIDEO_ITEM_BASE_ID + firstId + i);
            videoItem.setVideoId(draftVideo.getId());
            videoItem.setNum(i+1);
            list.add(videoItem);
        }
        draftVideoItemService.saveBatch(list);
        draftVideo.setFirst(VIDEO_ITEM_BASE_ID + firstId);
        save(draftVideo);
//     TODO:需要改进    短剧基本信息存redis
        redisTemplate.opsForValue().set("dj-info",draftVideo);

        return draftVideo.getId();
    }

    @Override
    @Transactional
//    修改状态
    public long updateVideo(VideoBaseDTO videoBaseDTO) {
//       草稿状态
        if (videoBaseDTO.getStatus()==VideoStatus.UP.getStatus() ){
            updateUpVideo(videoBaseDTO);
        }else {
            updateDraft(videoBaseDTO);
        }
        return videoBaseDTO.getId();
    }
//上架
    @Override
    @Transactional
    public void UpVideo(VideoBaseDTO videoBaseDTO) {
//        修改俩张表
        DraftVideo draftVideo = this.getById(videoBaseDTO.getId());
        LambdaQueryWrapper<DraftVideoItem> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(DraftVideoItem::getVideoId,videoBaseDTO.getId());
        List<DraftVideoItem> draftVideoItems = draftVideoItemService.list(queryWrapper);
//      转换为正式表数据
        Video video=BeanUtils.copyProperties(draftVideo, Video.class);
         video.setStatus(VideoStatus.UP.getStatus());
        video.setUpdateTime(LocalDateTime.now());
        video.setUpdater(100L);
        video.setUpTime(LocalDateTime.now());
        videoService.save(video);
        List<VideoItem> videoItems = BeanUtils.copyList(draftVideoItems, VideoItem.class);
           videoItemService.saveBatch(videoItems);
    }



    private void updateUpVideo(VideoBaseDTO videoBaseDTO) {
//        名称校验
        String name = videoBaseDTO.getName();
        LambdaQueryWrapper<DraftVideo> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DraftVideo::getName,name);
        DraftVideo draftVideo = baseMapper.selectOne(lambdaQueryWrapper);
        if (draftVideo!=null){
            throw new RuntimeException("短剧名存在");
        }
//        短剧的总集数是否一样
        if (videoBaseDTO.getTotalCount()!=draftVideo.getTotalCount()){
            throw new RuntimeException("短剧的总集数，不能修改");
        }
        baseMapper.updateById(videoBaseDTO);
    }

    /**
     * 更新草稿状态的短剧信息
     */
    private void updateDraft(VideoBaseDTO dto) {
//        名称校验
        String name = dto.getName();
        LambdaQueryWrapper<DraftVideo> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DraftVideo::getName,name);
        DraftVideo draftVideo = baseMapper.selectOne(lambdaQueryWrapper);
        if (draftVideo!=null){
            throw new RuntimeException("短剧名存在");
        }
        DraftVideo video = BeanUtils.copyBean(draftVideo, DraftVideo.class, ((source, target) -> {
            target.setUpdateTime(LocalDateTime.now());
            target.setUpdater(100L);
        }));
        DraftVideo oldVideo = baseMapper.selectById(dto.getId());
        if (video.getTotalCount().equals(oldVideo.getTotalCount())){
//            如果总集数改变，所有文件重新上传
            List<Long> oldItemIds=new ArrayList<>(oldVideo.getTotalCount());
            for (Integer i=0;i<oldVideo.getTotalCount();i++){
                oldItemIds.add(oldVideo.getFirst()+i);
            }
//            删除oss中的文件,直接删除上一级目录
            qiNiuService.deleteFolder(OSS_VIDEO_PREFIX + oldVideo.getId() + "/" + oldVideo.getFirst());
            draftVideoItemService.removeBatchByIds(oldItemIds);//删除老数据
//      插入新数据
            List<Long> itemIdRange = pkClient.getLongRange(VIDEO_ID_TYPE, video.getTotalCount());
            AtomicLong firstId = new AtomicLong(VIDEO_ITEM_BASE_ID + itemIdRange.get(0));
           video.setFirst(firstId.get());
            ArrayList<DraftVideoItem> items = new ArrayList<>();
            for (int i = 0; i <video.getTotalCount() ; i++) {
                DraftVideoItem videoItem = new DraftVideoItem();
                videoItem.setId(firstId.getAndIncrement());
                videoItem.setVideoId(video.getId());
                videoItem.setNum(i+1);
                videoItem.setStars(0);
                items.add(videoItem);
            }
            draftVideoItemService.saveBatch(items);
        }
        getBaseMapper().updateById(video);
    }
    /*
    EXCEL导入
     */
    @Override
    public void importVideo(MultipartFile file) throws IOException {
        List<UploadVideoDTO> list = EasyExcel.read(file.getInputStream())
                .head(UploadVideoDTO.class)
                .sheet().doReadSync();
        for (UploadVideoDTO dto : list) {
            DraftVideo draftVideo = BeanUtils.copyBean(dto, DraftVideo.class);
            draftVideo.setId(VIDEO_BASE_ID+pkClient.getLongKey(VIDEO_ID_TYPE));
//            补齐属性
            draftVideo.setCreateTime(LocalDateTime.now());
            draftVideo.setUpdateTime(LocalDateTime.now());
            draftVideo.setCreater(100L);
            draftVideo.setUpdater(100L);
            draftVideo.setPlayCount(0L);
            draftVideo.setFollowCount(0L);
//            上传图片
            String path=dto.getCoverUrl();
            String ext = path.substring(path.lastIndexOf("."));
            String fileName = OSS_VIDEO_PREFIX + draftVideo.getId() + "/" + draftVideo.getId() + ext;
            qiNiuService.upload(new File(path),fileName);
            draftVideo.setCoverUrl(fileName);
//            上传视频
            File videoFolder = new File(dto.getFirst());
            File[] files = videoFolder.listFiles();
            draftVideo.setTotalCount(files.length);
            List<Long> idRange = pkClient.getLongRange(VIDEO_ITEM_ID_TYPE, draftVideo.getTotalCount());
            long firstId = VIDEO_ITEM_BASE_ID + idRange.get(0);
            draftVideo.setFirst(firstId);//设置第一集
            ArrayList<DraftVideoItem> videoItems = new ArrayList<>();
            for (int i = 0; i < files.length; i++) {
                DraftVideoItem videoItem = new DraftVideoItem();
                videoItem.setId(firstId+i);
                String videoExt = files[i].getName().substring(path.lastIndexOf("."));
                String videoFileName = OSS_VIDEO_PREFIX + draftVideo.getId() + "/" + videoItem.getId() + "/" + videoItem.getId() + videoExt;
                  qiNiuService.upload(files[i],videoFileName);
                  videoItem.setVideoUrl(videoFileName);
                  videoItem.setNum(i+1);
                  videoItem.setStars(0);
                  videoItem.setVideoId(draftVideo.getId());
                videoItems.add(videoItem);
            }
            draftVideoItemService.saveBatch(videoItems);
            save(draftVideo);
        }

    }
//导出短剧,下载web版
    @Override
    public void exportVideo(HttpServletResponse response) throws IOException {
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("UTF-8");

            String fileName = URLEncoder.encode("短剧.xlsx", StandardCharsets.UTF_8);
            response.setHeader("Content-Disposition",
                    "attachment;filename=\"" + fileName + "\";filename*=UTF-8''" + fileName);

            List<DraftVideo> draftList = list();
            List<ExportDTO> exportDTOS = BeanUtils.copyList(draftList, ExportDTO.class); // 手动映射

            EasyExcel.write(response.getOutputStream(), ExportDTO.class)
                    .sheet("短剧")
                    .doWrite(exportDTOS);
        } catch (IOException e) {
            log.error("Excel导出失败", e);
        }
    }

    @Override
    public void videoDel(VideoBaseDTO videoBaseDTO) {
//           判断短剧的状态
        if (videoBaseDTO.getStatus().equals(VideoStatus.UP.getStatus())){
            throw new RuntimeException("请先下架短剧");
        }
//现在下架或草稿状态的短剧才能删除
//        短剧表的id
        Long id = videoBaseDTO.getId();
        LambdaQueryWrapper<DraftVideoItem> queryWrapper=new LambdaQueryWrapper<>();
//        对item表操作
        queryWrapper.eq(DraftVideoItem::getVideoId,id);
        List<DraftVideoItem> list = draftVideoItemService.list(queryWrapper);
        List<Long> longList = list.stream().map(DraftVideoItem::getId).collect(Collectors.toList());
//        先删除主表，再删除集数表
        this.removeById(id);
        draftVideoItemService.removeBatchByIds(longList);
    }
//短剧详情接口
    @Override
    public VideoInfoVO videoInfoById(Long id) {
        DraftVideo draftVideo = this.getById(id);
        VideoInfoVO videoInfoVO = BeanUtils.copyBean(draftVideo, VideoInfoVO.class);
        LambdaQueryWrapper<DraftVideoItem> lambdaQueryWrapper=
                new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DraftVideoItem::getVideoId,id);
        List<DraftVideoItem> list = draftVideoItemService.list(lambdaQueryWrapper);
        List<String> urlList = list.stream().map(draftVideoItem -> draftVideoItem.getVideoUrl()).collect(Collectors.toList());
      videoInfoVO.setItems(urlList);
        return videoInfoVO;
    }
//短剧播放页面信息
    @Override
    public VideoInfoVO selectOpenVideo(VideoBaseDTO videoBaseDTO) {
        Long itemId = videoBaseDTO.getId();
        DraftVideoItem draftVideoItem = draftVideoItemService.getById(itemId);
        ItemVO itemVO = BeanUtils.copyBean(draftVideoItem, ItemVO.class);
        Long videoId = draftVideoItem.getVideoId();
        DraftVideo draftVideo = getById(videoId);
        VideoInfoVO videoInfoVO = BeanUtils.copyBean(draftVideo, VideoInfoVO.class);
        videoInfoVO.setItemVO(itemVO);
        return videoInfoVO;
    }


}

